package com.example.demo.security.config;

import com.example.demo.annotation.AnonymousAccess;
import com.example.demo.security.JwtAccessDeniedHandler;
import com.example.demo.security.JwtAuthenticationEntryPoint;
import com.example.demo.security.TokenConfigurer;
import com.example.demo.security.TokenProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 配置类
 * @author zjj
 * @date 2021-05-26
 */
//定义配置类，替换xml配置项，SecurityConfig类中包含一个或者多个被@Bean注解的方法
@Configuration
//是spring  security的核心过滤器，请求的认证入口
@EnableWebSecurity
//认证是否有权访问，在方法执行之前执行，spring security默认是关闭的，开启该注解
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private CorsFilter corsFilter;
    @Autowired
    private JwtAccessDeniedHandler jwtAccessDeniedHandler;
    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Autowired
    private TokenProvider tokenProvider;

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults(){
        return new GrantedAuthorityDefaults("");
    }
//   密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception{
//        搜寻匿名标记的url
        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
        Set<String> anonymousUrls = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntity:handlerMethodMap.entrySet()) {
            HandlerMethod handlerMethod = infoEntity.getValue();
            AnonymousAccess anonymousAccess=handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            if(null != anonymousAccess){
                anonymousUrls.addAll(infoEntity.getKey().getPatternsCondition().getPatterns());
            }
        }
        httpSecurity
                //跨站请求禁用
                .csrf().disable()
                //基于JWT拦截的过滤器
                .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                //授权异常
                .exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .accessDeniedHandler(jwtAccessDeniedHandler)
                //防止iframe跨域
                .and()
                .headers()
                .frameOptions()
                .disable()

                //不创建会话
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //静态资源
                .and()
                .authorizeRequests()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js",
                        "/WebSocket/**"
                ).permitAll()
                .antMatchers(
                        "/swagger-resources/**",
                        "/api-docs",
                        "/doc.html",
                        "/api-docs-ext",
                        "/webjars/**",
                        "/v2/**",
                        "/swagger-ui.html"
                ).permitAll()
                .antMatchers("/avatar/**").permitAll()
                .antMatchers("/file/**").permitAll()
                .antMatchers("/druid/**").permitAll()
                .antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
                //允许匿名和带权限以及登录用户进行访问
                .antMatchers(anonymousUrls.toArray(new String[0])).permitAll()
                //所有请求都需要进行认证
                .anyRequest().authenticated()
                .and().apply(securityConfigurerAdapter());
    }
    private TokenConfigurer securityConfigurerAdapter(){
            return new TokenConfigurer(tokenProvider);
    }
}
